home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-06-09 | 11.9 KB | 422 lines | [TEXT/MPCC] |
- #include "LtDynamicArray.h"
-
- #include <UMemoryMgr.h>
-
- #define arrayIndex_Last 0x7FFFFFFF
- #define arrayIndex_Bad 0
-
- // ---------------------------------------------------------------------------
- // • LtDynamicArray
- // ---------------------------------------------------------------------------
- // /*const*/ruct an empty Array of items of the specified size
- //
- // Errors:
- // /*const*/ruction can fail if there is not enough memory to create
- // the Handle for storing the items
-
- template<class T>
- LtDynamicArray<T>::LtDynamicArray()
- {
- mItemSize = sizeof(T);
- mItemCount = 0;
- mItemsH = (T**)NewHandle(0);
- ThrowIfMemFail_(mItemsH);
- }
-
-
- // ---------------------------------------------------------------------------
- // • LtDynamicArray
- // ---------------------------------------------------------------------------
- // /*const*/ruct an Array of items using an existing Handle.
- //
- // Caller is responsible for ensuring that inItemsHandle is a valid
- // Handle of Pointer values
- //
- // The Array assumes ownership of inItemsHandle, meaning that the Array
- // is responsible for disposing of it.
-
- template<class T>
- LtDynamicArray<T>::LtDynamicArray(T **inItemsHandle)
- {
- mItemSize = sizeof(T);
- mItemsH = inItemsHandle;
- mItemCount = GetHandleSize((Handle)inItemsHandle) / mItemSize;
- }
-
-
- // ---------------------------------------------------------------------------
- // • ~LtDynamicArray
- // ---------------------------------------------------------------------------
- // Destructor
-
- template<class T>
- LtDynamicArray<T>::~LtDynamicArray()
- {
- if (mItemsH != nil) {
- DisposeHandle((Handle)mItemsH);
- }
- }
-
-
- // ---------------------------------------------------------------------------
- // • GetCount
- // ---------------------------------------------------------------------------
- // Return the number of items in an Array
-
- template<class T> Int32
- LtDynamicArray<T>::GetCount() const
- {
- return mItemCount;
- }
-
-
- // ---------------------------------------------------------------------------
- // • InsertItemsAt
- // ---------------------------------------------------------------------------
- // Insert items at the specified position in an Array
- //
- // inCount items are inserted into the Array starting at inAtIndex.
- // All items are set to the same value, as specified by inItem.
- //
- // If inAtIndex is greater than the number of items in the Array,
- // then the items are inserted after the last item.
- //
- // Errors:
- // Insertion can fail if there is not enough memory to store
- // the new items
-
- template <class T> void
- LtDynamicArray<T>::InsertItemsAt(
- Uint32 inCount,
- Int32 inAtIndex,
- T *inItem)
- {
- if (inCount < 1) { // Exit if nothing to insert
- return;
- }
- // Grow storage
- Int32 newCount = mItemCount + inCount;
- SetHandleSize((Handle) mItemsH, newCount * mItemSize);
- ThrowIfMemError_();
-
- Int32 saveCount = mItemCount;
- mItemCount = newCount;
-
- if (inAtIndex > saveCount) { // Check upper bound
- inAtIndex = saveCount + 1; // Insert at end of Array
-
- } else { // Insert at start or middle of Array
- if (inAtIndex < 1) { // Check lower bound
- inAtIndex = 1; // Insert at start of Array
- }
-
- if (saveCount > 0) { // Move existing items to make
- // room for new ones
- ShiftItems(inAtIndex, saveCount, inAtIndex + inCount);
- }
- }
- // Inserted items are all set
- // to the same value, if specified
- if (inItem != nil) {
- Int32 index = inAtIndex;
- do {
- PokeItem(index, inItem);
- } while (++index < inAtIndex + inCount);
- }
-
- }
-
-
- // ---------------------------------------------------------------------------
- // • RemoveItemsAt
- // ---------------------------------------------------------------------------
- // Remove items from an Array starting at a specified position
- //
- // Does nothing if inAtIndex is out of range. Checks if inCount would remove
- // items past the end of the Array, and adjusts it accordingly to remove
- // the items from inAtIndex to the end of the Array. That means you can pass
- // a large number (0x7FFFFFFF, the maximum, positive, 32-bit integer) to
- // remove the items from inAtIndex to the end of the Array.
-
- template<class T> void
- LtDynamicArray<T>::RemoveItemsAt(
- Uint32 inCount,
- Int32 inAtIndex)
- {
- // Check for special last item flag
- if (inAtIndex == arrayIndex_Last) {
- inAtIndex = mItemCount;
- }
- // Make sure inAtIndex is in range
- if (inAtIndex > 0 && inAtIndex <= mItemCount) {
-
- if (inAtIndex + inCount <= mItemCount) {
- // Removing items from the middle
- // Shift down items that are above
- // the ones being removed
- ShiftItems(inAtIndex + inCount, mItemCount, inAtIndex);
-
- } else { // Removing items at the end
- // Limit inCount to the number of items
- // from inWhere to the end
- inCount = mItemCount - inAtIndex + 1;
- }
-
- mItemCount -= inCount; // Reduce storage
- SetHandleSize((Handle) mItemsH, mItemCount * mItemSize);
- }
- }
-
-
- // ---------------------------------------------------------------------------
- // • FetchItemAt
- // ---------------------------------------------------------------------------
- // Pass back the Item at the specified index
- //
- // Returns true if an item exists at inIndex (and sets outItem)
- // Returns false if inIndex is out of range (and leave outItem unchanged)
-
- template<class T> Boolean
- LtDynamicArray<T>::FetchItemAt(
- Int32 inAtIndex,
- T *outItem) // Pointer to the item
- {
- Boolean itemExists = false;
-
- if (inAtIndex == arrayIndex_Last) {
- inAtIndex = mItemCount;
- }
- // Check that index is in range
- if (inAtIndex > 0 && inAtIndex <= mItemCount) {
- PeekItem(inAtIndex, outItem);
- itemExists = true;
- }
- return itemExists;
- }
-
-
- // ---------------------------------------------------------------------------
- // • SetItemAt
- // ---------------------------------------------------------------------------
- // Sets the value of the Item at the specified index
- //
- // inItem is a pointer to the item data. The Array makes and stores
- // a copy of the item data.
- //
- // Does nothing if inIndex is out of range
-
- template<class T> void
- LtDynamicArray<T>::SetItemAt(
- Int32 inAtIndex,
- const T *inItem) // Pointer to the item
- {
- if (inAtIndex == arrayIndex_Last) {
- inAtIndex = mItemCount;
- }
-
- // Check that index is in range
- if (inAtIndex > 0 && inAtIndex <= mItemCount) {
- PokeItem(inAtIndex, inItem);
- }
- }
-
-
- // ---------------------------------------------------------------------------
- // • SwapItems
- // ---------------------------------------------------------------------------
- // Swap the values of the Items at the specified indices
- //
- // Does nothing if either index is out of range
-
- template<class T> void
- LtDynamicArray<T>::SwapItems(
- Int32 inIndexA,
- Int32 inIndexB)
- {
- if (inIndexA == arrayIndex_Last) {
- inIndexA = mItemCount;
- }
- if (inIndexB == arrayIndex_Last) {
- inIndexB = mItemCount;
- }
- // Do nothing if either index is out
- // of range
- if ( (inIndexA > 0 && inIndexA <= mItemCount) &&
- (inIndexB > 0 && inIndexB <= mItemCount) ) {
-
- // Store copy of item A
- StPointerBlock itemACopy(mItemSize);
- PeekItem(inIndexA, (T*)itemACopy.mPtr);
-
- PokeItem(inIndexA, (T*)GetItemPtr(inIndexB)); // A = B
- PokeItem(inIndexB, (T*)itemACopy.mPtr); // B = Copy of A
- }
- }
-
-
- // ---------------------------------------------------------------------------
- // • MoveItem
- // ---------------------------------------------------------------------------
- // Move an item from one position to another in an Array. The net result
- // is the same as removing the item and inserting at a new position.
- //
- // Does nothing if either index is out of range
- //
- // Example:
- // BEFORE AFTER MoveItem(2, 6)
- // index 1 2 3 4 5 6 1 2 3 4 5 6
- // item a b c d e f a c d e b f
-
- template<class T> void
- LtDynamicArray<T>::MoveItem(
- Int32 inFromIndex,
- Int32 inToIndex)
- {
- if (inFromIndex == arrayIndex_Last) {
- inFromIndex = mItemCount;
- }
- if (inToIndex == arrayIndex_Last) {
- inToIndex = mItemCount;
- }
- // Do nothing if either index is out
- // of range or if "from" and "to"
- // indices are the same
- if ( (inFromIndex > 0 && inFromIndex <= mItemCount) &&
- (inToIndex > 0 && inToIndex <= mItemCount) &&
- (inFromIndex != inToIndex) ) {
-
- // Store copy of item to move
- StPointerBlock itemToMove(mItemSize);
- PeekItem(inFromIndex, (T*)itemToMove.mPtr);
-
- if (inFromIndex < inToIndex) {
- // Move item to a higher index
- // Shift items between "from" and "to"
- // down one spot
- ShiftItems(inFromIndex + 1, inToIndex, inFromIndex);
- } else {
- // Move item to a lower index
- // Shift items between "to" and "from"
- // up one spot
- ShiftItems(inToIndex, inFromIndex - 1, inToIndex + 1);
- }
-
- // Store item at new position
- PokeItem(inToIndex, (T*)itemToMove.mPtr);
- }
- }
-
-
- // ---------------------------------------------------------------------------
- // • FetchIndexOf
- // ---------------------------------------------------------------------------
- // Returns the index of the specified item within the Array
- //
- // Returns arrayIndex_Bad if the item is not in the Array
-
- template <class T> Int32
- LtDynamicArray<T>::FetchIndexOf(
- const T *inItem) const // Pointer to the item to find
- {
- Int32 findIndex = 0; // Search from beginning of Array
-
- while (++findIndex <= mItemCount) {
- if (BlocksAreEqual(inItem, GetItemPtr(findIndex), mItemSize)) {
- break;
- }
- }
-
- if (findIndex > mItemCount) { // Search stopped because we reached the
- findIndex = arrayIndex_Bad; // end without finding the item
- }
-
- return findIndex;
- }
-
-
- // ---------------------------------------------------------------------------
- // • Remove
- // ---------------------------------------------------------------------------
- // Remove an item from an Array
- template<class T> void
- LtDynamicArray<T>::Remove(
- const T *inItem) // Pointer to the item to remove
- {
- Int32 index = FetchIndexOf(inItem);
- if (index != arrayIndex_Bad) {
- RemoveItemsAt(1, index);
- }
- }
-
-
- // ---------------------------------------------------------------------------
- // • GetItemPtr
- // ---------------------------------------------------------------------------
- // Returns a pointer to the start of an Items data within the internal
- // storage Handle.
- //
- // WARNING: The return pointer references information inside a
- // relocatable block. This pointer will become invalid if the
- // Handle block moves.
-
- template <class T> T*
- LtDynamicArray<T>::GetItemPtr(
- Int32 inAtIndex) const
- {
- return &(*mItemsH)[inAtIndex - 1];/* + (inAtIndex - 1) * mItemSize);*/
- }
-
-
- // ---------------------------------------------------------------------------
- // • PeekItem
- // ---------------------------------------------------------------------------
- // Retrieves the Item at the specified index
- //
- // For internal use. Performs no bounds checking.
-
- template<class T>void
- LtDynamicArray<T>::PeekItem(
- Int32 inAtIndex,
- T *outItem) const
- {
- ::BlockMoveData(GetItemPtr(inAtIndex), outItem, mItemSize);
- }
-
-
- // ---------------------------------------------------------------------------
- // • PokeItem
- // ---------------------------------------------------------------------------
- // Stores the Item at a specified index
- //
- // For internal use. Performs no bounds checking.
-
- template <class T> void
- LtDynamicArray<T>::PokeItem(
- Int32 inAtIndex,
- const T *inItem)
- {
- ::BlockMoveData(inItem, GetItemPtr(inAtIndex), mItemSize);
- }
-
-
- // ---------------------------------------------------------------------------
- // • ShiftItems
- // ---------------------------------------------------------------------------
- // Moves items within the Handle used for internal storage
- // Moves items in the range inStartPos to inEndPos (inclusive) so
- // that those items start at index inDestPos, overwriting any items
- // that were there.
- //
- // For internal use. Performs no bounds checking.
-
- template <class T> void
- LtDynamicArray<T>::ShiftItems(
- Int32 inStartPos,
- Int32 inEndPos,
- Int32 inDestPos)
- {
- ::BlockMoveData(*mItemsH + (inStartPos - 1) /** mItemSize*/,
- *mItemsH + (inDestPos - 1) /** mItemSize*/,
- (inEndPos - inStartPos + 1) * mItemSize);
- }
-